package com.leigq.basaltools.util;

import cn.hutool.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 参数工具类
 *
 * @author leigq
 */
@Slf4j
public abstract class ParamUtils {

    /**
     * 将对象中的参数进行拼接，参数+参数值，like: a=aaa&b=222
     *
     * @param <T>            the type parameter
     * @param obj            待拼接属性的对象, 支持 Map 集合
     * @param skipFieldNames 需要跳过拼接的列
     * @return 拼接后的参数 ，不带最前面的？
     */
    public static <T> String toUrlParams(T obj, String... skipFieldNames) {
        return toUrlParams(obj, false, skipFieldNames);
    }


    /**
     * 将对象中的参数以参数首字母正序排序，然后拼接参数+参数值，like: a=aaa&b=222
     *
     * @param obj            待拼接属性的对象, 支持 Map 集合
     * @param skipFieldNames 需要跳过拼接的列
     * @return 拼接后的参数，不带最前面的？
     */
    public static <T> String toSortedUrlParams(T obj, String... skipFieldNames) {
        return toUrlParams(obj, true, skipFieldNames);
    }


    /**
     * 将对象中的参数进行拼接，参数+参数值，like: a=aaa&b=222
     *
     * @param <T>            the type parameter
     * @param obj            待拼接属性的对象, 支持 Map 集合
     * @param isSort         是否参数首字母正序排序
     * @param skipFieldNames 需要跳过拼接的列
     * @return 拼接后的参数 ，不带最前面的？
     */
    @SuppressWarnings(value = "unchecked")
    public static <T> String toUrlParams(T obj, boolean isSort, String... skipFieldNames) {
        if (Objects.isNull(obj)) {
            return null;
        }

        if (obj instanceof Map) {
            return getMapParam((Map<String, Object>) obj);
        }

        final Class<?> objClass = obj.getClass();

        // 获取子类所有字段
        final Field[] subclassFieldsArray = objClass.getDeclaredFields();

        if (ArrayUtil.isEmpty(subclassFieldsArray)) {
            return null;
        }

        // 用于保存最终所有字段
        List<Field> fields = Arrays.stream(subclassFieldsArray).collect(Collectors.toList());

        final Class<?> superclass = objClass.getSuperclass();

        // 父类不为空且父类不是 Object
        if (Objects.nonNull(superclass) && !Objects.equals(superclass.getSimpleName(), Object.class.getSimpleName())) {
            // 获取父类的属性，加入子类集合
            fields.addAll(Arrays.stream(superclass.getDeclaredFields()).collect(Collectors.toList()));
        }

        if (CollectionUtils.isEmpty(fields)) {
            return null;
        }

        // 将参数以参数首字母正序排序
        if (isSort) {
            fields = fields.stream().sorted(Comparator.comparing(Field::getName)).collect(Collectors.toList());
        }

        StringBuilder param = new StringBuilder();

        fields.forEach(field -> {
            final String fieldName = field.getName();
            // 跳过serialVersionUID
            if ("serialVersionUID".equals(fieldName)) {
                return;
            }
            // 是否跳过
            if (ArrayUtil.isNotEmpty(skipFieldNames) && isSkipField(fieldName, skipFieldNames)) {
                return;
            }
            field.setAccessible(true);
            final Object filedValue;
            try {
                filedValue = field.get(obj);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("拼接参数异常", e);
            }
            if (Objects.isNull(filedValue)) {
                return;
            }
            param.append(fieldName).append("=").append(filedValue).append("&");
        });
        // 去除最后一个 & 符号
        return param.replace(param.length() - 1, param.length(), "").toString();
    }


    /**
     * Gets map param.
     *
     * @param map the map
     * @return the map param
     */
    private static <V> String getMapParam(Map<String, V> map) {
        if (CollectionUtils.isEmpty(map)) {
            return null;
        }

        StringBuilder param = new StringBuilder();

        AtomicInteger index = new AtomicInteger(0);
        map.forEach((k, v) -> {
            param.append(k).append("=").append(v);
            if (index.get() != map.size() - 1) {
                param.append("&");
            }
            index.incrementAndGet();
        });
        return param.toString();
    }


    /**
     * 是否为跳过的字段
     *
     * @param fieldName      字段名称
     * @param skipFieldNames 跳过的字段名称列表
     * @return 是否为跳过的字段
     */
    private static boolean isSkipField(String fieldName, String... skipFieldNames) {
        if (Objects.isNull(skipFieldNames) || skipFieldNames.length == 0) {
            throw new NullPointerException("skipFieldNames can not be null");
        }
        return Arrays.asList(skipFieldNames).contains(fieldName);
    }
}